﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using Noris.Schedule.Support.Parser;

namespace Noris.Schedule.Support.Expressions
{
    #region class ParserExpressionEditorSetting : Generátor settingů pro Expressions
    /// <summary>
    /// ParserExpressionEditorSetting : Generátor settingů pro Expressions
    /// </summary>
    public static class ParserExpressionEditorSetting
    {
        #region Public static property, které vracejí settings
        /// <summary>
        /// ParserSetting pro ExpressionEditor
        /// </summary>
		public static ParserSetting GreenExpression { get { return _GetSettingGreenExpression(); } }
        #endregion
        #region Konstanty
        /// <summary>
        /// Název segmentu, který obsahuje běžný text: ExpText
        /// </summary>
        public const string EXP_TEXT = "ExpText";
        /// <summary>
        /// Název segmentu, který obsahuje proměnnou: ExpVariable
        /// </summary>
        public const string EXP_VARIABLE = "ExpVariable";
        /// <summary>
        /// Název segmentu, který obsahuje SQL výraz
        /// </summary>
        public const string SQL_CODE = ParserDefaultSetting.SQL_CODE;
        /// <summary>
        /// String, který uvozuje proměnnou: «{
        /// </summary>
		public const string EXP_VAR_BEGIN = "«{";
        /// <summary>
        /// String, který zakončuje proměnnou: }»
        /// </summary>
		public const string EXP_VAR_END = "}»";
        /// <summary>
        /// String, který uvozuje SQL výraz: «[
        /// </summary>
		public const string EXP_SQL_BEGIN = "«[";
        /// <summary>
        /// String, který zakončuje SQL výraz: ]»
        /// </summary>
        public const string EXP_SQL_END = "]»";
		#endregion
        #region Generátor settings pro GreenExpression
		private static ParserSetting _GetSettingGreenExpression()
		{
            ParserSetting setting = new ParserSetting("GreenExpression", EXP_TEXT);
			ParserSegmentSetting segment;

			// Text:
            segment = new ParserSegmentSetting(EXP_TEXT);
            segment.InnerSegmentsNames = new string[] { EXP_VARIABLE, Noris.Schedule.Support.Parser.ParserDefaultSetting.SQL_CODE };
            segment.AddRtfCodes(ParserSegmentValueType.Text,
                                new RtfItem[] { RtfItem.NewForeColor(Color.Black), RtfItem.NewFont("Arial"), RtfItem.NewFontStyle(RtfFontStyle.Regular) },
                                null);
			setting.SegmentSettingAdd(segment);

			// Proměnné:
            segment = new ParserSegmentSetting(EXP_VARIABLE);
			segment.BeginWith = EXP_VAR_BEGIN;
			segment.EndWith = new string[] { EXP_VAR_END };
            segment.AddRtfCodes(ParserSegmentValueType.Text,
                                new RtfItem[] { RtfItem.NewForeColor(Color.Blue), RtfItem.NewFont("Courier New CE"), RtfItem.NewFontStyle(RtfFontStyle.BoldOnly), RtfItem.NewProtect(true), RtfItem.NewHighlight(Color.FromArgb(186, 255, 255)) },
                                new RtfItem[] { RtfItem.NewForeColor(Color.Empty), RtfItem.NewHighlight(Color.Empty) });
            setting.SegmentSettingAdd(segment);

            // Vložíme do settingu deklaraci SQL kódu, a pozměníme v ni deklaraci Begin a End:
            ParserSegmentSetting sqlSettings = Noris.Schedule.Support.Parser.ParserDefaultSetting.AddSettingMsSql(setting);
			sqlSettings.BeginWith = EXP_SQL_BEGIN;
			sqlSettings.EndWith = new string[] { EXP_SQL_END };

            // Najdeme settingy SQL a vyměníme/doplníme v nich setting barvy pozadí:
            foreach (ParserSegmentSetting segm in setting.Segments.Where(s => (s.SegmentName.StartsWith(Noris.Schedule.Support.Parser.ParserDefaultSetting.SQL_))))
            {
                _AddRtfSet(segm, RtfItem.NewHighlight(Color.FromArgb(224, 255, 255)));
                _AddRtfReset(segm, RtfItem.NewHighlight(Color.Empty));
            }

            // Najdeme vhodné settingy pro SQL, a přidáme do nich možnost vložit navíc i naše proměnné:
            foreach (ParserSegmentSetting segm in setting.Segments.Where(s => (s.SegmentName == Noris.Schedule.Support.Parser.ParserDefaultSetting.SQL_CODE || s.SegmentName == Noris.Schedule.Support.Parser.ParserDefaultSetting.SQL_PARENTHESIS)))
                _AddInnerSegmentName(segm, EXP_VARIABLE);
            
			return setting;
		}
        /// <summary>
        /// Do dané deklarace segmentu přidá další jméno vnitřního segmentu (pokud tam ještě není).
        /// </summary>
        /// <param name="segm"></param>
        /// <param name="segmentName"></param>
        private static void _AddInnerSegmentName(ParserSegmentSetting segm, string segmentName)
        {
            if (segm == null || String.IsNullOrEmpty(segmentName)) return;
            if (segm.InnerSegmentsNames == null)
                segm.InnerSegmentsNames = new string[] { segmentName };
            else
            {
                List<string> names = new List<string>(segm.InnerSegmentsNames);
                if (!names.Contains(segmentName))
                {
                    names.Add(segmentName);
                    segm.InnerSegmentsNames = names.ToArray();
                }
            }
        }
        /// <summary>
        /// Do dané deklarace segmentu přidá další položku segm.RtfSet, anebo přepíše stávající položku se shodným typem (RtfItem.ItemType).
        /// </summary>
        /// <param name="segm"></param>
        /// <param name="rtfItem"></param>
        private static void _AddRtfSet(ParserSegmentSetting segm, RtfItem rtfItem)
        {
            if (segm == null || rtfItem == null) return;

            IEnumerable<ParserSegmentRtfCodePair> codePairs = segm.AllRtfCodePairs;
            foreach (ParserSegmentRtfCodePair codePair in codePairs)
            {
                if (codePair.CodeSet == null)
                    codePair.CodeSet = new RtfItem[] { rtfItem };
                else
                {
                    List<RtfItem> items = new List<RtfItem>(codePair.CodeSet);
                    int index = items.FindIndex(i => (i.ItemType == rtfItem.ItemType));
                    if (index >= 0)
                        items[index] = rtfItem;
                    else
                        items.Add(rtfItem);
                    codePair.CodeSet = items.ToArray();
                }
            }
        }
        /// <summary>
        /// Do dané deklarace segmentu přidá další položku segm.RtfReset, anebo přepíše stávající položku se shodným typem (RtfItem.ItemType).
        /// </summary>
        /// <param name="segm"></param>
        /// <param name="rtfItem"></param>
        private static void _AddRtfReset(ParserSegmentSetting segm, RtfItem rtfItem)
        {
            if (segm == null || rtfItem == null) return;

            IEnumerable<ParserSegmentRtfCodePair> codePairs = segm.AllRtfCodePairs;
            foreach (ParserSegmentRtfCodePair codePair in codePairs)
            {
                if (codePair.CodeReset == null)
                    codePair.CodeReset = new RtfItem[] { rtfItem };
                else
                {
                    List<RtfItem> items = new List<RtfItem>(codePair.CodeReset);
                    int index = items.FindIndex(i => (i.ItemType == rtfItem.ItemType));
                    if (index >= 0)
                        items[index] = rtfItem;
                    else
                        items.Add(rtfItem);
                    codePair.CodeReset = items.ToArray();
                }
            }
        }
		#endregion
	}
    #endregion
}
